﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "AlgorithmIntersect.h"
#include "AlgorithmProperty.h"
#include "GbmpBuiltInParameterDefinitionsNew.h"
#include "GbmpCalculatorBase.h"
#include "GcmpBuiltInParameterDefinitions.h"
#include "GraphicsNodeIdHistoryUtils.h"
#include "ICutRelationshipBehavior.h"
#include "IElementModelShape.h"
#include "IElementParameters.h"
#include "IGraphicsBRepFace.h"
#include "IGraphicsElementShape.h"
#include "IGraphicsNodePathCollector.h"
#include "IInstance.h"
#include "IOpeningRelationshipBehavior.h"
#include "IParameter.h"
#include "IParameterDefinitionLibrary.h"
#include "IType.h"
#include "StructureBasicWall.h"
#include "StructureInstanceUtils.h"
#include "IGeometryRelationshipComponent.h"

#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

using namespace gcmp;
using namespace std;
namespace
{
    double GetWallArea(const IInstance *pInstance)
    {
        IDocument* pDoc = pInstance->GetDocument();
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pDoc, L"IDocument不存在",L"GDMPLab",L"2024-03-30");

        bool cutOrOpened = false;
        const IGeometryRelationshipComponent* pGeometryRepCpt = pInstance->GetGeometryRelationshipComponent();
        if (pGeometryRepCpt)
        {
            if (!cutOrOpened)
            {
                //扣减判断
                const ICutRelationshipBehavior* cutRelationshipBehavior = pGeometryRepCpt->GetCutRelationship();
                if (cutRelationshipBehavior && !cutRelationshipBehavior->GetElementCutIds().empty())
                {
                    cutOrOpened = true;
                }
            }

            if (!cutOrOpened)
            {
                //开洞判断
                const IOpeningRelationshipBehavior* openingRelationshipBehavior = pGeometryRepCpt->GetOpeningRelationship();
                if (openingRelationshipBehavior && !openingRelationshipBehavior->GetElementOpeningIds().empty())
                {
                    cutOrOpened = true;
                }
            }
        }

        //外墙面Id
        vector<GraphicsNodeId> exteriorFaceIds;
        {
            const IElementBasicInformation * pBasicInfo = pInstance->GetBasicInformation();
            DBG_WARN_AND_RETURN_FALSE_UNLESS(pBasicInfo, L"pBasicInfo为空",L"GDMPLab",L"2024-03-30");
            const IType* pType = pBasicInfo->GetType();
            DBG_WARN_AND_RETURN_FALSE_UNLESS(pType, L"pType为空",L"GDMPLab",L"2024-03-30");
            OwnerPtr<IParameter> exteriorFaceParam = ELEMENT_PARAMETER(pType, ExteriorFaceNodeTagBuiltInParameter);
            DBG_WARN_AND_RETURN_FALSE_UNLESS(IParameter::IsValidParameter(exteriorFaceParam), L"没有预期参数",L"GDMPLab",L"2024-03-30");
            GraphicsNodeId exteriorFaceId(exteriorFaceParam->GetValueAsInt());
            if (cutOrOpened)
            {
                bool ret = GraphicsNodeIdHistoryUtils::GetCurrentGraphicsNodeId(pInstance, exteriorFaceId, exteriorFaceIds);
                DBG_WARN_AND_RETURN_FALSE_UNLESS(ret, L"侧面ID追溯与预期不符",L"GDMPLab",L"2024-03-30");
            }
            else
            {
                exteriorFaceIds.push_back(exteriorFaceId);
            }
        }

        //内墙面Id
        vector<GraphicsNodeId> interiorFaceIds;
        {
            const IElementBasicInformation * pBasicInfo = pInstance->GetBasicInformation();
            DBG_WARN_AND_RETURN_FALSE_UNLESS(pBasicInfo, L"pBasicInfo为空",L"GDMPLab",L"2024-03-30");
            const IType* pType = pBasicInfo->GetType();
            DBG_WARN_AND_RETURN_FALSE_UNLESS(pType, L"pType为空",L"GDMPLab",L"2024-03-30");
            OwnerPtr<IParameter> interiorFaceParam = ELEMENT_PARAMETER(pType, InteriorFaceNodeTagBuiltInParameter);
            DBG_WARN_AND_RETURN_FALSE_UNLESS(IParameter::IsValidParameter(interiorFaceParam), L"没有预期参数",L"GDMPLab",L"2024-03-30");
            GraphicsNodeId interiorFaceId(interiorFaceParam->GetValueAsInt());
            if (cutOrOpened)
            {
                bool ret = GraphicsNodeIdHistoryUtils::GetCurrentGraphicsNodeId(pInstance, interiorFaceId, interiorFaceIds);
                DBG_WARN_AND_RETURN_FALSE_UNLESS(ret, L"侧面ID追溯与预期不符",L"GDMPLab",L"2024-03-30");
            }
            else
            {
                interiorFaceIds.push_back(interiorFaceId);
            }
        }

        const IGraphicsElementShape* pShape = pInstance->GetElementModelShape()->GetGraphicsElementShape();
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pShape, L"pShape为空",L"GDMPLab",L"2024-03-30");
        OwnerPtr<IGraphicsNodePathCollector> collecter = IGraphicsNodePathCollector::Create(pDoc, pShape);

        //外表面
        std::vector<const IGraphicsBRepFace*> exteriorSideFaces;
        FOR_EACH(exteriorFaceId, exteriorFaceIds)
        {
            OwnerPtr<IGraphicsNodePathCollection> exteriorFacePaths = collecter->CollectGraphicsBRepFaceById(GraphicsNodeId(exteriorFaceId));
            DBG_WARN_AND_RETURN_FALSE_UNLESS(exteriorFacePaths->GetPaths().size() == 1, L"查找FACE失败",L"GDMPLab",L"2024-03-30");

            GraphicsNodeAndTransform exteriorNode = exteriorFacePaths->GetPaths().front()->GetLastGraphicsNodeAndTransform();
            const gcmp::IGraphicsBRepFace *pExteriorGFaceNode = dynamic_cast<const gcmp::IGraphicsBRepFace*>(exteriorNode.m_wpGraphicsNode.Get());
            DBG_WARN_AND_RETURN_FALSE_UNLESS(pExteriorGFaceNode, L"没有预期参数",L"GDMPLab",L"2024-03-30");

            exteriorSideFaces.push_back(pExteriorGFaceNode);
        }

        //内表面
        std::vector<const IGraphicsBRepFace*> interiorSideFaces;
        FOR_EACH(interiorFaceId, interiorFaceIds)
        {
            OwnerPtr<IGraphicsNodePathCollection> interiorFacePaths = collecter->CollectGraphicsBRepFaceById(GraphicsNodeId(interiorFaceId));
            DBG_WARN_AND_RETURN_FALSE_UNLESS(interiorFacePaths->GetPaths().size() == 1, L"查找FACE失败",L"GDMPLab",L"2024-03-30");

            GraphicsNodeAndTransform interiorNode = interiorFacePaths->GetPaths().front()->GetLastGraphicsNodeAndTransform();
            const gcmp::IGraphicsBRepFace *pInteriorGFaceNode = dynamic_cast<const gcmp::IGraphicsBRepFace*>(interiorNode.m_wpGraphicsNode.Get());
            DBG_WARN_AND_RETURN_FALSE_UNLESS(pInteriorGFaceNode, L"没有预期参数",L"GDMPLab",L"2024-03-30");

            interiorSideFaces.push_back(pInteriorGFaceNode);
        }

        // 计算面积：外表面
        double exteriorSideArea = 0;
        FOR_EACH(exteriorSideFace, exteriorSideFaces)
        {
            double areaTemp = AlgorithmProperty::GetArea(exteriorSideFace->GetGmFace());
            exteriorSideArea += areaTemp;
        }

        // 计算面积：内表面
        double interiorSideArea = 0;
        FOR_EACH(interiorSideFace, interiorSideFaces)
        {
            double areaTemp = AlgorithmProperty::GetArea(interiorSideFace->GetGmFace());
            interiorSideArea += areaTemp;
        }

        // 取面积较大者
        return exteriorSideArea>interiorSideArea ? exteriorSideArea : interiorSideArea;
    }
}

namespace gcmp
{
    class WallAreaCalculator : public gcmp::GbmpCalculatorBase
    {
        DECLARE_CALCULATOR(WallAreaCalculator, IInstance)
    public:
        WallAreaCalculator(IDocument* pDoc, const RegenDataId& outputDataId) : GbmpCalculatorBase(pDoc, outputDataId) {}
        virtual void ReportInputDataIds(std::vector<RegenDataId> & dataIds) const override;
        virtual void Execute() override;
    };

    void WallAreaCalculator::ReportInputDataIds(std::vector<RegenDataId> & dataIds) const
    {
        IInstance *pTarget = GetElement<IInstance>();
        DBG_WARN_AND_RETURN_VOID_UNLESS(pTarget, L"计算器的目标对象为空",L"GDMPLab",L"2024-03-30");
        const IElementModelShape *pGrepBehavior = pTarget->GetElementModelShape();
        DBG_WARN_AND_RETURN_VOID_UNLESS(pGrepBehavior, L"构件IGraphicsElementShapeBehavior为空",L"GDMPLab",L"2024-03-30");
        dataIds.push_back(pGrepBehavior->GetGraphicsElementShapeRdId());
    }

    void WallAreaCalculator::Execute()
    {
        IInstance *pInstance = GetElement<IInstance>();
        DBG_WARN_AND_RETURN_VOID_UNLESS(pInstance, L"计算器的目标对象为空",L"GDMPLab",L"2024-03-30");

        // 计算面积
        double area = GetWallArea(pInstance);
        UniIdentity paramUId = PARAMETER_UID(AreaBuiltInParameter);
        StructureInstanceUtils::SetInstanceOutputParamValueByParamUid(pInstance, area, paramUId);
    }
}

IMPLEMENT_CALCULATOR_CREATOR(gcmp, WallAreaCalculator);